﻿//using OpenTK.Graphics.OpenGL;
//using System;
//using System.Collections;
//using System.Collections.Concurrent;
//using System.Collections.Generic;
//using System.Linq;
//using System.Net.Sockets;
//using System.Runtime.CompilerServices;
//using System.Text;
//using System.Threading.Tasks;
//using System.Xml.Linq;

//namespace LightCAD.Three
//{

//    public class MergeGroup : Group
//    {
//        public sealed class GeoGroupInfo
//        {
//            public GeoGroup childGroup;
//            public Object3D obj;
//            public int startInMerge;
//        }
//        public sealed class MGeoGroup : GeoGroup
//        {
//            public JsArr<GeoGroupInfo> grpInfos;
//            public MGeoGroup(JsObj<Object3D, ObjInMergeInfo> objVertexRange, JsArr<GeoGroupInfo> grpInfos, int materialIndex, JsArr<int> mIndexes)
//            {
//                this.grpInfos = grpInfos;
//                this.materialIndex = materialIndex;
//                this.start = mIndexes.length;
//                var startOffset = 0;
//                for (int i = 0; i < grpInfos.length; i++)
//                {
//                    var grpInfo = grpInfos[i];
//                    grpInfo.startInMerge = startOffset;
//                    var grp = grpInfo.childGroup;
//                    var obj = grpInfo.obj;
//                    var indexOffset = objVertexRange[obj].vertexStart;
//                    var geo = (obj as IGeometry).getGeometry();
//                    var idxArr = geo.index.intArray.slice2<int>(grp.start, grp.count);
//                    for (int j = 0; j < idxArr.Length; j++)
//                        mIndexes.push(idxArr[j] + indexOffset);
//                    startOffset += grp.count;
//                }
//                this.count = startOffset;
//            }
//            public static JsArr<GeoGroup> createMGeoGroups(JsObj<Object3D, ObjInMergeInfo> objVertexRange, JsObj<Material, JsArr<GeoGroupInfo>> materialGrps, out JsArr<int> indexes)
//            {
//                var mgrps = new JsArr<GeoGroup>(materialGrps.Count);
//                indexes = new JsArr<int>();
//                int matIndex = 0;
//                foreach (var item in materialGrps)
//                {
//                    var mat = item.Key;
//                    var grpInfos = item.Value;
//                    mgrps[matIndex] = new MGeoGroup(objVertexRange, grpInfos, matIndex, indexes);
//                    matIndex++;
//                }
//                return mgrps;
//            }
//        }
//        public sealed class ObjInMergeInfo
//        {
//            public int vertexStart;
//            public int objIndex;
//        }
//        public sealed class MergedObjectInfo
//        {
//            public JsObj<Object3D, ObjInMergeInfo> objInfos;
//            public JsObj<Material, JsArr<GeoGroupInfo>> materialGrps;
//            public IMergedObject mergedObj;
//            public JsArr<UniformsGroup> uniformsGroups;
//            public UniformsGroup mergeItemMatrix;
//            public UniformsGroup colorState;
//            public readonly bool useAlbUBO;

//            public MergedObjectInfo(bool useAblUBO)
//            {
//                this.useAlbUBO = useAblUBO;
//            }
//            // 元素在渲染前后更改材质的UBO
//            public void beforRenderAction(WebGLRenderer render, Object3D _object, Camera camera, object arg1, object materialObj = null, object arg3 = null)
//            {
//                var currMaterial = materialObj as Material;
//                if (useAlbUBO)
//                {
//                    currMaterial.defines.set("USE_ALBUBO", "");
//                    currMaterial.defines.set("Merge_Max_Size", Merge_Max_Size);
//                    currMaterial.uniformsGroups = this.uniformsGroups;
//                }
//                else
//                    currMaterial.defines.set("USE_PACKCOLOR", "");
//            }
//            public void afterRenderAction(WebGLRenderer render, Object3D _object, Camera camera, object arg1 = null, object materialObj = null, object arg3 = null)
//            {
//                var currMaterial = materialObj as Material;
//                if (useAlbUBO)
//                {
//                    this.uniformsGroups.forEach(ug => ug.uniforms.forEach(u => u.needsUpdate = false));
//                    currMaterial.defines.remove("USE_ALBUBO");
//                    currMaterial.defines.remove("Merge_Max_Size");
//                    currMaterial.uniformsGroups = null;
//                }
//                else
//                    currMaterial.defines.remove("USE_PACKCOLOR");
//            }
//            public void init()
//            {
//                (mergedObj as Object3D).onBeforeRenderAction = beforRenderAction;
//                (mergedObj as Object3D).onAfterRenderAction = afterRenderAction;
//                if (useAlbUBO)
//                {
//                    this.mergeItemMatrix = new UniformsGroup();
//                    this.mergeItemMatrix.setName("MergeItemMatrixData");
//                    var posArr = new Vector3[Merge_Max_Size];
//                    var scaleArr = new Vector3[Merge_Max_Size];
//                    var quaternionArr = new Vector4[Merge_Max_Size];
//                    for (int i = 0; i < Merge_Max_Size; i++)
//                    {
//                        posArr[i] = new Vector3(0, 0, 0);
//                        scaleArr[i] = new Vector3(1, 1, 1);
//                        quaternionArr[i] = new Vector4(0, 0, 0, 1);
//                    }
//                    this.mergeItemMatrix.add(new Uniform(posArr));
//                    this.mergeItemMatrix.add(new Uniform(scaleArr));
//                    this.mergeItemMatrix.add(new Uniform(quaternionArr));

//                    var colorArr = new float[Merge_Max_Size];
//                    var sate = new int[Merge_Max_Size];
//                    var defaultColor = new Color();
//                    for (int i = 0; i < Merge_Max_Size; i++)
//                    {
//                        colorArr[i] = packColor(defaultColor);
//                        sate[i] = int.MaxValue;
//                    }
//                    this.colorState = new UniformsGroup();
//                    this.colorState.setName("ColorStateData");
//                    this.colorState.add(new Uniform(colorArr));
//                    this.colorState.add(new Uniform(sate));
//                    this.uniformsGroups = new JsArr<UniformsGroup>();

//                    this.uniformsGroups.push(this.mergeItemMatrix);
//                    this.uniformsGroups.push(this.colorState);
//                }
//            }
//            public void dispose()
//            {
//                (mergedObj as Object3D).onBeforeRenderAction = null;
//                (mergedObj as Object3D).onAfterRenderAction = null;
//                this.uniformsGroups?.ForEach(u => u.dispose());
//                this.uniformsGroups?.Clear();
//                this.uniformsGroups = null;
//            }

//            public void refreshMatAndColor()
//            {
//                var objs = objInfos.Keys.ToArray();
//                for (int i = 0; i < objs.Length; i++)
//                {
//                    var obj = objs[i];
//                    refreshChildMatrix(i, obj);
//                    refreshChildColorState(i, obj);
//                }
//                if (!useAlbUBO)
//                {
//                    var geo = (this.mergedObj as IGeometry).getGeometry();
//                    geo.attributes.position.needsUpdate = true;
//                    geo.attributes.normal.needsUpdate = true;
//                    geo.attributes.packColor.needsUpdate = true;
//                }
//            }
//            public void refreshChildMatrixs(IList<Object3D> objs)
//            {
//                for (int i = 0; i < objs.Count; i++)
//                {
//                    refreshChildMatrix(objs[i]);
//                }
//                if (!useAlbUBO)
//                {
//                    var geo = (this.mergedObj as IGeometry).getGeometry();
//                    geo.attributes.position.needsUpdate = true;
//                    geo.attributes.normal.needsUpdate = true;
//                }
//            }
//            private void refreshChildMatrix(int idx, Object3D obj)
//            {
//                if (useAlbUBO)
//                {
//                    var posUniform = mergeItemMatrix.uniforms[0];
//                    var posArr = posUniform.value as Vector3[];
//                    posArr[idx].copy(obj.position);
//                    posUniform.needsUpdate = true;

//                    var scaleUniform = mergeItemMatrix.uniforms[1];
//                    var scaleArr = scaleUniform.value as Vector3[];
//                    scaleArr[idx].copy(obj.scale);
//                    scaleUniform.needsUpdate = true;

//                    var quaternionUniform = mergeItemMatrix.uniforms[2];
//                    var quaternionArr = quaternionUniform.value as Vector4[];
//                    var quaternion = obj.quaternion.setFromEuler(obj.rotation);
//                    quaternionArr[idx].set(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
//                    quaternionUniform.needsUpdate = true;
//                }
//                else
//                {
//                    var _vec3 = ThreadContext.getCurrThreadContext().vector3;
//                    var mgeo = (this.mergedObj as IGeometry).getGeometry();
//                    var oGeo = (obj as IGeometry).getGeometry();

//                    var oPosition = oGeo.attributes.position;
//                    var mPosition = mgeo.attributes.position;
//                    var oNormal = oGeo.attributes.normal;
//                    var mNormal = mgeo.attributes.normal;
//                    var normalMat = oNormal != null ? new Matrix3().getNormalMatrix(obj.matrix) : null;
//                    var vertexOffset = this.objInfos[obj].vertexStart;
//                    for (int i = 0; i < oPosition.count; i++)
//                    {
//                        var offset = (vertexOffset + i) * 3;
//                        _vec3.fromArray(oPosition.array, i * 3);
//                        _vec3.applyMatrix4(obj.matrix);
//                        _vec3.toArray(mPosition.array, offset);
//                        if (oNormal != null)
//                        {
//                            _vec3.fromArray(oNormal.array, i * 3);
//                            _vec3.applyNormalMatrix(normalMat);
//                            packNormal(_vec3, mNormal.arrObj as sbyte[], offset);
//                        }
//                    }
//                }
//            }
//            private void refreshChildMatrix(Object3D obj)
//            {
//                refreshChildMatrix(this.objInfos[obj].objIndex, obj);
//            }
//            public void refreshChildColorStates(IList<Object3D> objs)
//            {

//                if (!useAlbUBO)
//                {
//                    var mgeo = (this.mergedObj as IGeometry).getGeometry();
//                    var mPosition = mgeo.attributes.position;
//                    bool createNew = true;
//                    if (mgeo.attributes.packColor == null)
//                    {
//                        mgeo.attributes.packColor = new BufferAttribute(new float[mPosition.count], 1);
//                    }
//                    else if (mgeo.attributes.packColor.arrObj.Length != mPosition.count)
//                    {
//                        mgeo.attributes.packColor.arrObj = new float[mPosition.count];
//                    }
//                    else createNew = false;
//                    if (createNew)
//                    {
//                        refreshChildColorStates(this.objInfos.Keys.ToArray());
//                        return;
//                    }
//                }
//                for (int i = 0; i < objs.Count; i++)
//                {
//                    refreshChildColorState(objs[i]);
//                }
//                if (!useAlbUBO)
//                {
//                    var mgeo = (this.mergedObj as IGeometry).getGeometry();
//                    mgeo.attributes.packColor.needsUpdate = true;
//                }
//            }
//            private void refreshChildColorState(int idx, Object3D obj)
//            {
//                if (obj.color == null)
//                    obj.color = new Color();
//                if (useAlbUBO)
//                {
//                    var colorUniform = colorState.uniforms[0];
//                    var colorArr = colorUniform.value as float[];
//                    colorArr[idx] = packColor(obj.color);
//                    colorUniform.needsUpdate = true;
//                }
//                else
//                {
//                    var mgeo = (this.mergedObj as IGeometry).getGeometry();
//                    var ogeo = (obj as IGeometry).getGeometry();
//                    var mPosition = mgeo.attributes.position;
//                    var oPosition = ogeo.attributes.position;
//                    if (mgeo.attributes.packColor == null)
//                    {
//                        mgeo.attributes.packColor = new BufferAttribute(new float[mPosition.count], 1);
//                    }
//                    else if (mgeo.attributes.packColor.arrObj.Length != mPosition.count)
//                    {
//                        mgeo.attributes.packColor.arrObj = new float[mPosition.count];
//                    }
//                    var pcolorAtt = mgeo.attributes.packColor;
//                    var vertexOffset = this.objInfos[obj].vertexStart;
//                    var _packColor = packColor(obj.color);
//                    var _packColorArr = pcolorAtt.arrObj as float[];
//                    for (int i = 0; i < oPosition.count; i++)
//                    {
//                        _packColorArr[i + vertexOffset] = _packColor;
//                    }
//                }
//            }
//            private void refreshChildColorState(Object3D obj)
//            {
//                refreshChildColorState(this.objInfos[obj].objIndex, obj);
//            }
//            public void applyVisibleChange()
//            {
//                if (this.mergedObj is IMultiIndirectObject)
//                    (this.mergedObj as IMultiIndirectObject).initIndexCmds();
//            }
//        }
//        public enum MergeOptEnum
//        {
//            Create,
//            Add,
//            ReBuild,
//            ReBUildIndexOnly,
//            Delete
//        }


//        //private readonly static Material _invisibleMat = new Material() { visible = false };
//        public bool merged;
//        public const bool indirectDraw = true;//暂不考虑不是间接渲染的情况
//        public readonly bool pack = true;
//        public readonly static int Merge_Max_Size = (int)Math.Floor(WebGLCapabilities.Max_UniformBlock_Size / 48.0);

//        public Func<Material, string> getMaterialKeyFunc;

//        internal JsObj<IMergedObject, MergedObjectInfo> mergeObjInfoMap;
//        private JsObj<Object3D, IMergedObject> mergedMap;
//        private JsObj<JsArr<MergedMesh>> cateMMeshes;
//        private JsObj<JsArr<MergedLine>> cateMLines;
//        private int meshNum = 0;
//        private int lineNum = 0;
//        public int calculateUBONum()
//        {
//            var num = Math.Ceiling(meshNum / (float)Merge_Max_Size) + Math.Ceiling(lineNum / (float)Merge_Max_Size);
//            return (int)num;
//        }
//        //defer changes
//        private ConcurrentDictionary<int, Object3D> visibleChangeCollection = new ConcurrentDictionary<int, Object3D>();
//        private ConcurrentDictionary<int, Object3D> attributeChangeCollection = new ConcurrentDictionary<int, Object3D>();
//        private ConcurrentDictionary<int, Object3D> materialChangeCollection = new ConcurrentDictionary<int, Object3D>();
//        private ConcurrentDictionary<int, Object3D> colorChangeCollection = new ConcurrentDictionary<int, Object3D>();
//        private ConcurrentDictionary<int, Object3D> matrixChangeCollection = new ConcurrentDictionary<int, Object3D>();
//        public bool? useAlbUBO { get; private set; } = null;
//        public MergeGroup() : base()
//        {
//            this.type = "MergeGroup";
//            this.merged = false;
//            this.mergedMap = new JsObj<Object3D, IMergedObject>();
//        }
//        public void merge(bool useAlbUBO = true)
//        {
//            if (merged)
//                throw new THREE.Error("MergeGroup不能重复merge");
//            this.useAlbUBO = useAlbUBO;
//            clearChangeCollection();
//            this.cateMMeshes = new JsObj<JsArr<MergedMesh>>();
//            this.cateMLines = new JsObj<JsArr<MergedLine>>();
//            this.mergeObjInfoMap = new JsObj<IMergedObject, MergedObjectInfo>();
//            groupByCate(this.children, out var cateMeshes, out var cateLines);
//            createOrUpateMergeObj(cateMeshes, cateLines);
//            this.merged = true;
//        }
//        public void unmerge()
//        {
//            if (this.merged)
//            {
//                var _objects = this.children;
//                for (int i = 0; i < _objects.length; i++)
//                {
//                    removeEvent(_objects[i]);
//                }
//                //已经融合buffer的情况下删除元素
//                this.mergedMap.Clear();
//                foreach (var item in this.mergeObjInfoMap)
//                {
//                    var mobj = item.Key;
//                    (mobj as IGeometry).getGeometry().dispose();
//                    var mObjInfo = item.Value;
//                    mObjInfo.dispose();
//                }
//                this.mergeObjInfoMap.Clear();
//                this.merged = false;
//            }
//        }
//        private void clearChangeCollection()
//        {
//            visibleChangeCollection.Clear();
//            attributeChangeCollection.Clear();
//            materialChangeCollection.Clear();
//            colorChangeCollection.Clear();
//            matrixChangeCollection.Clear();
//        }
//        public override void updateMatrixWorld(bool force = false)
//        {
//            if (this.matrixAutoUpdate) this.updateMatrix();
//            if (this.matrixWorldNeedsUpdate || force)
//            {
//                if (this.parent == null)
//                {
//                    this.matrixWorld.copy(this.matrix);
//                }
//                else
//                {
//                    this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
//                }
//                this.matrixWorldNeedsUpdate = false;
//                force = true;
//            }
//            // update children
//            var children = this.children;
//            if (this.merged)
//            {
//                var mobjGrps = matrixChangeCollection.Values.ToLookup(obj => this.mergedMap[obj]).ToArray();
//                Parallel.For(0, mobjGrps.Length, (grpIdx) =>
//                {
//                    var mobj = mobjGrps[grpIdx].Key;
//                    var mobjInfo = this.mergeObjInfoMap[mobj];
//                    var childObjs = mobjGrps[grpIdx].ToArray();
//                    mobjInfo.refreshChildMatrixs(childObjs);
//                    for (int i = 0; i < childObjs.Length; i++)
//                    {
//                        childObjs[i].updateMatrixWorld(force);
//                    }
//                });
//            }
//            else
//                for (int i = 0, l = children.Count; i < l; i++)
//                {
//                    var child = children[i];
//                    if (child.matrixAutoUpdate)
//                    {
//                        child.updateMatrixWorld(force);
//                    }
//                }
//        }
//        public override Object3D add(params Object3D[] _objects)
//        {
//            for (int i = 0; i < _objects.Length; i++)
//            {
//                var obj = _objects[i];
//                if (obj is Mesh)
//                    meshNum++;
//                else if (obj is Line)
//                    lineNum++;
//                base.add(obj);
//                addEvents(obj);
//            }
//            if (this.merged)
//            {
//                //已经融合buffer的情况下添加元素
//                groupByCate(_objects.ToJsArr(), out var cateMeshes, out var cateLines);
//                createOrUpateMergeObj(cateMeshes, cateLines);
//            }
//            return this;
//        }
//        public override Object3D remove(params Object3D[] _objects)
//        {
//            for (int i = 0; i < _objects.Length; i++)
//            {
//                var obj = _objects[i];
//                base.remove(_objects[i]);
//                if (obj is Mesh)
//                    meshNum--;
//                else if (obj is Line)
//                    lineNum--;
//                removeEvent(_objects[i]);
//            }
//            if (this.merged)
//            {
//                //已经融合buffer的情况下删除元素
//                groupByCate(_objects, out var cateMeshes, out var cateLines);
//                createOrUpateMergeObj(cateMeshes, cateLines, true);
//            }
//            return this;
//        }
//        private void addEvents(Object3D @object)
//        {
//            @object.addEventListener("visibleChanged", addvisibleChangeCollection);
//            @object.addEventListener("attributeChanged", addattributeChangeCollection);
//            @object.addEventListener("materialChanged", addmaterialChangeCollection);
//            @object.addEventListener("colorChanged", addcolorChangeCollection);
//            @object.addEventListener("matrixChanged", addmatrixChangeCollection);
//        }
//        private void removeEvent(Object3D @object)
//        {
//            @object.removeEventListener("visibleChanged", addvisibleChangeCollection);
//            @object.removeEventListener("attributeChanged", addattributeChangeCollection);
//            @object.removeEventListener("materialChanged", addmaterialChangeCollection);
//            @object.removeEventListener("colorChanged", addcolorChangeCollection);
//            @object.removeEventListener("matrixChanged", addmatrixChangeCollection);
//        }
//        //event
//        private void addvisibleChangeCollection(EventArgs args)
//        {
//            var obj = (args.target as Object3D);
//            this.visibleChangeCollection.AddOrUpdate(obj.id, obj, addOrUpdateCollection);
//        }

//        private void addattributeChangeCollection(EventArgs args)
//        {
//            var obj = (args.target as Object3D);
//            this.attributeChangeCollection.AddOrUpdate(obj.id, obj, addOrUpdateCollection);
//        }
//        private void addmaterialChangeCollection(EventArgs args)
//        {
//            var obj = (args.target as Object3D);
//            this.materialChangeCollection.AddOrUpdate(obj.id, obj, addOrUpdateCollection);
//        }
//        private void addcolorChangeCollection(EventArgs args)
//        {
//            var obj = (args.target as Object3D);
//            this.colorChangeCollection.AddOrUpdate(obj.id, obj, addOrUpdateCollection);
//        }
//        private void addmatrixChangeCollection(EventArgs args)
//        {
//            var obj = (args.target as Object3D);
//            this.matrixChangeCollection.AddOrUpdate(obj.id, obj, addOrUpdateCollection);

//        }
//        private Object3D addOrUpdateCollection(int key, Object3D obj)
//        {
//            return obj;
//        }

//        private void groupByCate(IList<Object3D> children, out JsObj<JsArr<Mesh>> cateMeshes, out JsObj<JsArr<Line>> cateLines)
//        {
//            cateMeshes = new JsObj<JsArr<Mesh>>();
//            cateLines = new JsObj<JsArr<Line>>();
//            for (var i = 0; i < children.Count; i++)
//            {
//                var obj = children[i];
//                if (!(obj is Mesh) && !(obj is Line)) continue;
//                if (obj is InstancedMesh) continue;
//                var cate = obj.category;
//                if (obj is Mesh)
//                {
//                    if (!cateMeshes.ContainsKey(cate))
//                        cateMeshes[cate] = new JsArr<Mesh>();
//                    var curMeshes = cateMeshes[cate];
//                    curMeshes.push(obj as Mesh);
//                }
//                else if (obj is Line)
//                {
//                    if (!cateLines.ContainsKey(cate))
//                        cateLines[cate] = new JsArr<Line> { };
//                    var curLines = cateLines[cate];
//                    curLines.push(obj as Line);
//                }
//            }
//        }
//        public void createOrUpateMergeObj(JsObj<JsArr<Mesh>> cateMeshes, JsObj<JsArr<Line>> cateLines, bool delete = false)
//        {
//            foreach (var item in cateMeshes)
//            {
//                var cate = item.Key;
//                var meshGrps = item.Value;
//                if (!this.cateMMeshes.ContainsKey(cate))
//                    this.cateMMeshes[cate] = new JsArr<MergedMesh>();
//                if (delete)
//                {
//                    var mmeshes = meshGrps.ToLookup(m => this.mergedMap[m]);
//                    foreach (var mitem in mmeshes)
//                    {
//                        var mmesh = mitem.Key as MergedMesh;
//                        if (mmesh == null)
//                            continue;
//                        var meshes = mitem.ToJsArr();
//                        var minfo = this.mergeObjInfoMap[mmesh];
//                        mergeObjects<Mesh>(minfo, meshes, MergeOptEnum.Delete);
//                    }
//                }
//                else
//                {
//                    var lates = this.cateMMeshes[cate].LastOrDefault();
//                    while (meshGrps?.length > 0)
//                    {

//                        if (lates == null || isFullMerged(lates))
//                        {
//                            meshGrps.spliteTwoPart(Merge_Max_Size, out var fp, out var sp);
//                            meshGrps = fp;
//                            var mMInfo = mergeObjects<Mesh>(null, meshGrps, MergeOptEnum.Create);
//                            this.mergeObjInfoMap.Add(mMInfo.mergedObj, mMInfo);
//                            this.cateMMeshes[cate].push(mMInfo.mergedObj as MergedMesh);
//                            lates = mMInfo.mergedObj as MergedMesh;
//                            meshGrps = sp;
//                        }
//                        else
//                        {
//                            var mergeObjInfo = this.mergeObjInfoMap[lates];
//                            var spaceCount = Merge_Max_Size - mergeObjInfo.objInfos.Count;
//                            meshGrps.spliteTwoPart(spaceCount, out var fp, out var sp);
//                            meshGrps = fp;
//                            mergeObjects<Mesh>(mergeObjInfo, meshGrps, MergeOptEnum.Add);
//                            meshGrps = sp;
//                        }
//                    }
//                }
//            }
//            //TODO Line
//            foreach (var item in cateLines)
//            {
//                var cate = item.Key;
//                var lineGrps = item.Value;
//                if (!this.cateMLines.ContainsKey(cate))
//                    this.cateMLines[cate] = new JsArr<MergedLine>();
//                if (delete)
//                {
//                    var mLines = lineGrps.ToLookup(m => this.mergedMap[m]);
//                    foreach (var litem in mLines)
//                    {
//                        var mline = litem.Key as MergedLine;
//                        if (mline == null)
//                            continue;
//                        var lines = litem.ToJsArr();
//                        var minfo = this.mergeObjInfoMap[mline];
//                        mergeObjects<Line>(minfo, lines, MergeOptEnum.Delete);
//                    }
//                }
//                else
//                {
//                    var lates = this.cateMLines[cate].LastOrDefault();
//                    while (lineGrps?.length > 0)
//                    {

//                        if (lates == null || isFullMerged(lates))
//                        {
//                            lineGrps.spliteTwoPart(Merge_Max_Size, out var fp, out var sp);
//                            lineGrps = fp;
//                            var mLInfo = mergeObjects<Line>(null, lineGrps, MergeOptEnum.Create);
//                            this.mergeObjInfoMap.Add(mLInfo.mergedObj, mLInfo);
//                            this.cateMLines[cate].push(mLInfo.mergedObj as MergedLine);
//                            lates = mLInfo.mergedObj as MergedLine;
//                            lineGrps = sp;
//                        }
//                        else
//                        {
//                            var mergeObjInfo = this.mergeObjInfoMap[lates];
//                            var spaceCount = Merge_Max_Size - mergeObjInfo.objInfos.Count;
//                            lineGrps.spliteTwoPart(spaceCount, out var fp, out var sp);
//                            lineGrps = fp;
//                            mergeObjects<Line>(mergeObjInfo, lineGrps, MergeOptEnum.Add);
//                            lineGrps = sp;
//                        }
//                    }
//                }
//            }
//        }
//        private bool isFullMerged(IMergedObject obj)
//        {
//            return this.mergeObjInfoMap[obj].objInfos.Count == Merge_Max_Size;
//        }
//        /// <summary>
//        /// 操作合并对象的核心函数 可以通过参数组合实现  创建、增加、删除、重构buffer、重构index  
//        /// </summary>
//        /// <typeparam name="T">Mesh/Line</typeparam>
//        /// <typeparam name="TMerge">MeredMesh/MergedLine</typeparam>
//        /// <param name="mergeObjInfo">合并对象信息</param>
//        /// <param name="objs">要操作的对象集合</param>
//        /// <param name="delete">是否从合并对象中删除objs</param>
//        /// <returns></returns>
//        private MergedObjectInfo mergeObjects<T>(MergedObjectInfo mergeObjInfo, JsArr<T> objs, MergeOptEnum operation) where T : Object3D
//        {
//            int offset = 0, vertexOffset = 0;
//            bool create = false, add = false, reBuild = false, reGroupIndexOnly = false, delete = false;
//            switch (operation)
//            {
//                case MergeOptEnum.Create:
//                    create = true;
//                    break;
//                case MergeOptEnum.Add:
//                    add = true;
//                    offset = mergeObjInfo.objInfos.Count;
//                    break;
//                case MergeOptEnum.ReBuild:
//                    reBuild = true;
//                    break;
//                case MergeOptEnum.ReBUildIndexOnly:
//                    reGroupIndexOnly = true;
//                    break;
//                case MergeOptEnum.Delete:
//                    delete = true;
//                    break;
//                default:
//                    break;
//            }

//            JsObj<Object3D, ObjInMergeInfo> objInfos = mergeObjInfo?.objInfos ?? new JsObj<Object3D, ObjInMergeInfo>();
//            JsObj<Material, JsArr<GeoGroupInfo>> materialGrps = mergeObjInfo?.materialGrps ?? new JsObj<Material, JsArr<GeoGroupInfo>>();
//            if (add)
//            {
//                vertexOffset = (mergeObjInfo.mergedObj as IGeometry).getGeometry().attributes.position.count;
//            }
//            else if (reBuild)
//            {
//                objs = objInfos.Keys.Cast<T>().ToJsArr();
//                objInfos.Clear();
//                materialGrps.Clear();
//            }
//            else if (delete)
//            {
//                objs.forEach(o =>
//                {
//                    o.isMerged = false;
//                    objInfos.remove(o);
//                    this.mergedMap.remove(o);
//                });
//                objs = objInfos.Keys.Cast<T>().ToJsArr();
//                objInfos.Clear();
//                materialGrps.Clear();
//                if (objs.length == 0)//没元素了就清空
//                {
//                    var mObj = mergeObjInfo.mergedObj;
//                    var geo = (mObj as IGeometry).getGeometry();
//                    geo.dispose();
//                    if (mObj is Mesh)
//                    {
//                        var mMesh = mObj as MergedMesh;
//                        this.mergeObjInfoMap.remove(mMesh);
//                        this.cateMMeshes[mMesh.category].remove(mMesh);
//                    }
//                    else
//                    {
//                        var mLine = mObj as MergedLine;
//                        this.mergeObjInfoMap.remove(mLine);
//                        this.cateMLines[mLine.category].remove(mLine);
//                    }
//                    return null;
//                }
//            }
//            else if (reGroupIndexOnly)
//            {
//                objs = objInfos.Keys.Cast<T>().ToJsArr();
//                materialGrps.Clear();
//            }


//            JsArr<double> posArr = reGroupIndexOnly ? null : new JsArr<double>();
//            JsArr<double> normalArr = reGroupIndexOnly ? null : new JsArr<double>();
//            JsArr<double> uvArr = reGroupIndexOnly ? null : new JsArr<double>();
//            JsArr<int> objIndexArr = reGroupIndexOnly ? null : new JsArr<int>();
//            for (int i = 0; i < objs.length; i++)
//            {
//                var obj = objs[i];
//                var geo = (obj as IGeometry).getGeometry();
//                collectObjGroups(materialGrps, obj);
//                if (reGroupIndexOnly)
//                    continue;
//                ObjInMergeInfo objInfo;
//                if (objInfos.ContainsKey(obj))
//                    objInfo = objInfos[obj];
//                else
//                {
//                    objInfo = new ObjInMergeInfo();
//                    objInfos[obj] = objInfo;
//                }
//                objInfo.vertexStart = posArr.length / 3 + vertexOffset;
//                objInfo.objIndex = i + offset;
//                var attrs = geo.attributes;
//                posArr.push(attrs.position.array);

//                if (attrs.normal != null)
//                    normalArr.push(attrs.normal.array);

//                if (attrs.uv != null)
//                    uvArr.push(attrs.uv.array);

//                for (int j = 0; j < attrs.position.count; j++)
//                {
//                    objIndexArr.push(i + offset);
//                }

//                obj.isMerged = true;
//            }

//            var mgrps = MGeoGroup.createMGeoGroups(objInfos, materialGrps, out var indexJsArr);

//            BufferAttribute mPosAtt, mNormalAtt, mUVAtt, mMIndexAtt;
//            if (create)
//            {
//                //index
//                var mGeo = new BufferGeometry();
//                mGeo.groups = mgrps;
//                mGeo.setIndex(new BufferAttribute(indexJsArr.ToArray(), 1, false));

//                //attribute
//                mPosAtt = new Float32BufferAttribute(getFillArray(posArr), 3, false);
//                mMIndexAtt = new BufferAttribute(getFillArray(objIndexArr), 1, false);
//                if (pack)
//                {
//                    mNormalAtt = new BufferAttribute(getFillArray(packNormal(normalArr.ToArray())), 3, true);
//                    mUVAtt = new BufferAttribute(getFillArray(packUV(uvArr.ToArray())), 2, false);
//                    foreach (var material in materialGrps.Keys)
//                    {
//                        material.map?.repeat.set(1.0 / 255, 1.0 / 255);
//                    }
//                }
//                else
//                {
//                    mNormalAtt = new BufferAttribute(getFillArray(normalArr), 3, false);
//                    mUVAtt = new BufferAttribute(getFillArray(uvArr), 2, false);
//                    foreach (var material in materialGrps.Keys)
//                    {
//                        material.map?.repeat.set(1, 1);
//                    }
//                }
//                mGeo.setAttribute("position", mPosAtt);
//                mGeo.setAttribute("normal", mNormalAtt);
//                mGeo.setAttribute("uv", mUVAtt);
//                if (useAlbUBO.Value)
//                    mGeo.setAttribute("objIndex", mMIndexAtt);

//                mergeObjInfo = new MergedObjectInfo(useAlbUBO.Value)
//                {
//                    objInfos = objInfos,
//                    materialGrps = materialGrps
//                };
//                if (objs[0] is Mesh)
//                {
//                    var mMesh = indirectDraw ? new MultiIndirectMesh(mGeo, materialGrps.Keys.ToArray()) : new MergedMesh(mGeo, materialGrps.Keys.ToArray());
//                    mergeObjInfo.mergedObj = mMesh;
//                }
//                else
//                {
//                    var mLine = indirectDraw ? new MultiIndirectLine(mGeo, materialGrps.Keys.ToArray()) : new MergedLine(mGeo, materialGrps.Keys.ToArray());
//                    mergeObjInfo.mergedObj = mLine;
//                }
//                (mergeObjInfo.mergedObj as Object3D).category = objs[0].category;
//                mergeObjInfo.init();
//            }
//            else
//            {
//                var mGeo = (mergeObjInfo.mergedObj as IGeometry).getGeometry();
//                mGeo.index.intArray = indexJsArr.ToArray();
//                mGeo.index.count = indexJsArr.length;
//                mGeo.groups = mgrps;
//                mGeo.index.needsUpdate = true;
//                //材质集合也要随变更修改
//                (mergeObjInfo.mergedObj as IMaterialObject).setMaterials(materialGrps.Keys.ToJsArr());
//                if (!reGroupIndexOnly)
//                {
//                    mPosAtt = mGeo.attributes.position;
//                    mNormalAtt = mGeo.attributes.normal;
//                    mUVAtt = mGeo.attributes.uv;
//                    mMIndexAtt = mGeo.attributes["objIndex"];
//                    //重构顶点buffer
//                    if (reBuild || delete || add)
//                    {
//                        mGeo.dispose();//销毁之前的buffer
//                        if (pack)
//                        {
//                            mNormalAtt.arrObj = getFillArray(add ? mNormalAtt.arrObj as sbyte[] : null, packNormal(normalArr));
//                            mUVAtt.arrObj = getFillArray(mUVAtt.arrObj as byte[], packUV(uvArr));
//                        }
//                        else
//                        {
//                            mNormalAtt.array = getFillArray(add ? mNormalAtt.array : null, (normalArr));
//                            mUVAtt.array = getFillArray(add ? mUVAtt.array : null, (uvArr));
//                        }
//                        mPosAtt.array = getFillArray(add ? mPosAtt.array : null, posArr);
//                        if (useAlbUBO.Value && mMIndexAtt != null)
//                            mMIndexAtt.arrObj = getFillArray(add ? mMIndexAtt.intArray : null, objIndexArr);
//                    }
//                    else
//                    {
//                        throw new THREE.Error("合并对象的意外操作");
//                    }
//                    mPosAtt.count = mPosAtt.array.Length / 3;
//                    mPosAtt.needsUpdate = true;
//                    mNormalAtt.count = mPosAtt.count;
//                    mNormalAtt.needsUpdate = true;
//                    mUVAtt.count = mPosAtt.count;
//                    mUVAtt.needsUpdate = true;
//                    if (useAlbUBO.Value && mMIndexAtt != null)
//                    {
//                        mMIndexAtt.count = mPosAtt.count;
//                        mMIndexAtt.needsUpdate = true;
//                    }
//                }
//            }
//            if (create || add)
//            {
//                objs.forEach(o =>
//                {   //添加ismerged对象和合并后对象的映射
//                    this.mergedMap[o] = mergeObjInfo.mergedObj;
//                });
//            }
//            if (create || reBuild || delete)
//                mergeObjInfo.refreshMatAndColor();
//            else if (add)
//            {
//                var allObjs = objInfos.Keys.ToList();
//                var start = allObjs.IndexOf(objs[0]);
//                mergeObjInfo.refreshChildMatrixs(allObjs);
//                mergeObjInfo.refreshChildColorStates(allObjs);
//            }
//             (mergeObjInfo.mergedObj as IMultiIndirectObject)?.initIndexCmds();
//            return mergeObjInfo;
//        }
//        private static void collectObjGroups(JsObj<Material, JsArr<GeoGroupInfo>> matGeoGrpInfos, Object3D obj)
//        {
//            var materials = (obj as IMaterialObject).getMaterials();
//            var geo = (obj as IGeometry).getGeometry();
//            if (obj is LineSegments)
//            {
//                if (geo.index == null)
//                {
//                    var posCount = geo.attributes.position.count;
//                    var idxArr = new int[posCount];
//                    for (int i = 0; i < posCount; i++)
//                    {
//                        idxArr[i] = i;
//                    }
//                    geo.setIndex(idxArr);
//                }
//            }
//            if (materials.length == 1)
//            {
//                geo.groups = new JsArr<GeoGroup>
//                    {
//                        new GeoGroup
//                        {
//                            start=0,
//                            count=geo.index.count
//                        }
//                    };
//            }
//            for (int i = 0; i < materials.length; i++)
//            {
//                var material = materials[i];
//                var grp = geo.groups[i];
//                //if (obj.visible == false)
//                //    material = _invisibleMat;
//                if (!matGeoGrpInfos.ContainsKey(material))
//                    matGeoGrpInfos[material] = new JsArr<GeoGroupInfo>();
//                matGeoGrpInfos[material].push(new GeoGroupInfo { childGroup = grp, obj = obj });
//            }
//        }
//        private static T[] getFillArray<T>(IList<T> src, IList<T> newarr)
//        {
//            var srcCount = src?.Count ?? 0;
//            var destArr = new T[srcCount + newarr.Count];
//            for (int i = 0; i < destArr.Length; i++)
//            {
//                if (i < srcCount)
//                    destArr[i] = src[i];
//                else
//                    destArr[i] = newarr[i - srcCount];
//            }
//            return destArr;
//        }
//        private static T[] getFillArray<T>(IList<T> newarr)
//        {
//            return getFillArray(null, newarr);
//        }
//        public void upateChildrenDeferChanges()
//        {
//            JsObj<int, IMergedObject> hasRebuild = new JsObj<int, IMergedObject>();
//            if (attributeChangeCollection.Count > 0)
//            {
//                var grpByMergeObj = attributeChangeCollection.ToLookup(v => mergedMap[v.Value]);
//                foreach (var item in grpByMergeObj)
//                {
//                    var mergedObj = item.Key;
//                    //重构所有顶点和group等等
//                    if (mergedObj is MergedMesh)
//                    {
//                        var mergeInfo = mergeObjInfoMap[mergedObj as MergedMesh];
//                        mergeObjects<Mesh>(mergeInfo, null, MergeOptEnum.ReBuild);
//                    }
//                    else
//                    {
//                        var mergeInfo = mergeObjInfoMap[mergedObj as MergedLine];
//                        mergeObjects<Line>(mergeInfo, null, MergeOptEnum.ReBuild);
//                    }
//                    hasRebuild.Add((mergedObj as Object3D).id, mergedObj);
//                }
//                attributeChangeCollection.Clear();
//            }
//            //if (!indirectDraw)//不是间接渲染的话 可见性变更和材质变更就合并
//            //{
//            //    materialChangeCollection.push(visibleChangeCollection.Values.ToArray());
//            //    visibleChangeCollection.Clear();
//            //}
//            if (materialChangeCollection.Count > 0)
//            {
//                var grpByMergeObj = materialChangeCollection.ToLookup(v => mergedMap[v.Value]);
//                foreach (var item in grpByMergeObj)
//                {
//                    var mergedObj = item.Key;
//                    if (hasRebuild.ContainsKey((mergedObj as Object3D).id))
//                        continue;
//                    //重构材质Group映射
//                    if (mergedObj is MergedMesh)
//                    {
//                        var mergeInfo = mergeObjInfoMap[mergedObj as MergedMesh];
//                        mergeObjects<Mesh>(mergeInfo, null, MergeOptEnum.ReBUildIndexOnly);
//                    }
//                    else
//                    {
//                        var mergeInfo = mergeObjInfoMap[mergedObj as MergedLine];
//                        mergeObjects<Line>(mergeInfo, null, MergeOptEnum.ReBUildIndexOnly);
//                    }
//                }
//                materialChangeCollection.Clear();
//            }

//            if (visibleChangeCollection.Count > 0)
//            {
//                var grpByMergeObj = visibleChangeCollection.ToLookup(v => mergedMap[v.Value]);
//                foreach (var item in grpByMergeObj)
//                {
//                    var mergedObj = item.Key;
//                    if (hasRebuild.ContainsKey((mergedObj as Object3D).id))
//                        continue;
//                    mergeObjInfoMap[mergedObj].applyVisibleChange();
//                }
//                visibleChangeCollection.Clear();
//            }

//            if (colorChangeCollection.Count > 0)
//            {
//                var mObjs = new Dictionary<MergedObjectInfo, List<Object3D>>();
//                foreach (var item in colorChangeCollection)
//                {
//                    var child = item.Value;
//                    var mobj = this.mergedMap[child];
//                    if (mobj == null)
//                        this.mergedMap.remove(child);
//                    else
//                    {
//                        var mObjInfo = this.mergeObjInfoMap[mobj];
//                        if (!mObjs.ContainsKey(mObjInfo))
//                        {
//                            mObjs.Add(mObjInfo, new List<Object3D>());
//                        }
//                        mObjs[mObjInfo].Add(child);
//                    }
//                }
//                foreach (var item in mObjs)
//                {
//                    item.Key.refreshChildColorStates(item.Value);
//                }
//                colorChangeCollection.Clear();
//            }

//        }
//    }
//    public interface IMergedObject
//    {
//    }

//    public class MergedMesh : Mesh, IMergedObject
//    {
//        public MergedMesh(BufferGeometry geometry, params Material[] material) : base(geometry, material)
//        {
//            this.type = "MergedMesh";
//        }

//    }
//    public class MergedLine : LineSegments, IMergedObject
//    {
//        public JsArr<UniformsGroup> uniformsGroups;
//        public UniformsGroup mergeItemMaterix;
//        public UniformsGroup colorState;
//        public MergedLine(BufferGeometry geometry, Material material) : base(geometry, material)
//        {
//            this.type = "MergedLine";
//        }
//        public MergedLine(BufferGeometry geometry, params Material[] material) : base(geometry, material)
//        {
//            this.type = "MergedLine";
//        }
//    }
//}
